package cn.airfei.aircore.core.generator;

import cn.airfei.aircore.core.properties.CodeGeneratorProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;

import java.util.*;

/**
 * @description: 自动生成代码类
 * @author: air
 * @create: 2019-12-19 14:48
 **/
public class CodeGenerator {
    private DataSourceProperties dataSourceProperties;
    private CodeGeneratorProperty codeGeneratorProperty;

    public void generator(DataSourceProperties dataSourceProperties, CodeGeneratorProperty codeGeneratorProperty) {
        this.codeGeneratorProperty = codeGeneratorProperty;
        this.dataSourceProperties = dataSourceProperties;

        // 生成实体类
        generatorStorage("vo");
        generatorStorage("entity");
        generatorStorage("dto");

        // 生成service
        generatorService("service");
        generatorService("domainService");

        // 生成pom.xml
        generatorPomXml("storages");
        generatorPomXml("services");
        generatorPomXml("infrastructure");

        // 生成mapper
        generatorInfrastructure();

        generatorConvertor();

        // 生成接口
        generatorControllerApi();
        generatorController();

        // 生成config
        generatorConfig("swagger");
        generatorConfig("cors");
        generatorConfig("redisson");


    }


    /**
     * @param storageType vo,dto,entity
     */
    private void generatorStorage(String storageType) {
        System.out.println("------------fastAutoGeneratorCustom generatorStorage--------------");
        Map<String, Object> injectionConfigMap = injectionConfigMap();
        FastAutoGenerator fastAutoGeneratorCustom = FastAutoGenerator.create(dataSourceProperties.getUrl(), dataSourceProperties.getUsername(), dataSourceProperties.getPassword())
                .globalConfig(builder -> {
                    builder.author(codeGeneratorProperty.getAuthor()) // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .outputDir(codeGeneratorProperty.getOutputDir() + "storages/src/main/java"); // 指定输出目录
                })
                //注入配置
                .injectionConfig(injectionConfig -> {
                    injectionConfig.customMap(injectionConfigMap);
                })
                .packageConfig(builder -> {
                    builder.parent(codeGeneratorProperty.getParent() + ".storages") // 设置父包名
                            .entity(storageType)
                            .moduleName(codeGeneratorProperty.getModuleName()) // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, codeGeneratorProperty.getOutputDir() + "/storages")); // 设置mapperXml生成路径
                })
                .templateConfig(builder -> {
                    if (storageType.equals("vo")) {
                        builder.entity("/templates/air/vo.java")
                                .disable(TemplateType.CONTROLLER, TemplateType.SERVICE, TemplateType.MAPPER, TemplateType.SERVICEIMPL, TemplateType.XML);
                    }

                    if (storageType.equals("dto")) {
                        builder.entity("/templates/air/dto.java")
                                .disable(TemplateType.CONTROLLER, TemplateType.SERVICE, TemplateType.MAPPER, TemplateType.SERVICEIMPL, TemplateType.XML);
                    }
                    if (storageType.equals("entity")) {
                        builder.entity("/templates/air/entity.java")
                                .disable(TemplateType.CONTROLLER, TemplateType.SERVICE, TemplateType.MAPPER, TemplateType.SERVICEIMPL, TemplateType.XML);
                    }
                })
                .strategyConfig(builder -> {
                    if (codeGeneratorProperty.getIncludeTables() != null) {
                        builder.addExclude(codeGeneratorProperty.getIncludeTables().split(",")); // 设置需要生成的表名
                    }
                    builder.addTablePrefix(codeGeneratorProperty.getTablePrefix()); // 设置过滤表前缀

                    String suffix = null;
                    if (storageType.equals("vo")) {
                        suffix = "Vo";
                    }
                    if (storageType.equals("dto")) {
                        suffix = "Dto";
                    }
                    if (storageType.equals("entity")) {
                        suffix = "";
                    }
                    builder.entityBuilder().naming(NamingStrategy.underline_to_camel).columnNaming(NamingStrategy.underline_to_camel)
                            .enableLombok()
                            .idType(IdType.ASSIGN_ID).formatFileName("%s" + suffix);

                    if (storageType.equals("entity")) {
//                        builder.entityBuilder().enableTableFieldAnnotation();
                    }


                })
                .templateEngine(new FreemarkerTemplateEngine());// 使用Freemarker引擎模板，默认的是Velocity引擎模板

        fastAutoGeneratorCustom.execute();
    }


    /**
     * @param serviceType service,domainService
     */
    private void generatorService(String serviceType) {
        System.out.println("------------fastAutoGeneratorCustom generatorService--------------");
        Map<String, Object> injectionConfigMap = injectionConfigMap();

        FastAutoGenerator fastAutoGeneratorCustom = FastAutoGenerator.create(dataSourceProperties.getUrl(), dataSourceProperties.getUsername(), dataSourceProperties.getPassword())
                .globalConfig(builder -> {
                    builder.author(codeGeneratorProperty.getAuthor()) // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .outputDir(codeGeneratorProperty.getOutputDir() + "services/src/main/java"); // 指定输出目录
                })
                //注入配置
                .injectionConfig(injectionConfig -> {
                    injectionConfig.customMap(injectionConfigMap);
                })
                .packageConfig(builder -> {
                    builder.parent(codeGeneratorProperty.getParent() + ".services") // 设置父包名
                            .service(serviceType)
                            .serviceImpl(serviceType + ".impl")
                            .moduleName(codeGeneratorProperty.getModuleName()) // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, "/tmp")); // 设置mapperXml生成路径
                })
                .templateConfig(builder -> {
                    if (serviceType.equals("domainService")) {
                        builder.service("/templates/air/domainservice.java")
                                .serviceImpl("/templates/air/domainserviceImpl.java")
                                .disable(TemplateType.CONTROLLER, TemplateType.MAPPER, TemplateType.ENTITY);
                    }

                    if (serviceType.equals("service")) {
                        builder.service("/templates/air/service.java")
                                .serviceImpl("/templates/air/serviceImpl.java")
                                .disable(TemplateType.CONTROLLER, TemplateType.MAPPER, TemplateType.ENTITY);
                    }

                })
                .strategyConfig(builder -> {
                    if (codeGeneratorProperty.getIncludeTables() != null) {
                        builder.addExclude(codeGeneratorProperty.getIncludeTables().split(",")); // 设置需要生成的表名
                    }
                    builder.addTablePrefix(codeGeneratorProperty.getTablePrefix()); // 设置过滤表前缀

                    if (serviceType.equals("domainService")) {
                        builder.serviceBuilder().formatServiceFileName("%sDomainService").formatServiceImplFileName("%sDomainServiceImpl");
                    }
                })
                .templateEngine(new FreemarkerTemplateEngine());// 使用Freemarker引擎模板，默认的是Velocity引擎模板

        fastAutoGeneratorCustom.execute();
    }


    private void generatorController() {
        System.out.println("------------fastAutoGeneratorCustom generatorController--------------");
        Map<String, Object> injectionConfigMap = injectionConfigMap();

        FastAutoGenerator fastAutoGeneratorCustom = FastAutoGenerator.create(dataSourceProperties.getUrl(), dataSourceProperties.getUsername(), dataSourceProperties.getPassword())
                .globalConfig(builder -> {
                    builder.author(codeGeneratorProperty.getAuthor()) // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .outputDir(codeGeneratorProperty.getProjectPath() + "/src/main/java/"); // 指定输出目录
                })
                //注入配置
                .injectionConfig(injectionConfig -> {
                    injectionConfig.customMap(injectionConfigMap);
                })
                .packageConfig(builder -> {
                    builder.parent(codeGeneratorProperty.getParent()) // 设置父包名
                            .moduleName(codeGeneratorProperty.getModuleName()) // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, "/tmp")); // 设置mapperXml生成路径
                })
                .templateConfig(builder -> {
                    builder.controller("/templates/air/controller.java")
                            .disable(TemplateType.SERVICEIMPL, TemplateType.SERVICE, TemplateType.MAPPER, TemplateType.ENTITY, TemplateType.XML);

                })
                .strategyConfig(builder -> {
                    if (codeGeneratorProperty.getIncludeTables() != null) {
                        builder.addExclude(codeGeneratorProperty.getIncludeTables().split(",")); // 设置需要生成的表名
                    }
                    builder.addTablePrefix(codeGeneratorProperty.getTablePrefix()); // 设置过滤表前缀
                    builder.controllerBuilder().enableRestStyle();

                })
                .templateEngine(new FreemarkerTemplateEngine());// 使用Freemarker引擎模板，默认的是Velocity引擎模板

        fastAutoGeneratorCustom.execute();
    }


    private void generatorControllerApi() {
        System.out.println("------------fastAutoGeneratorCustom generatorControllerApi--------------");
        Map<String, Object> injectionConfigMap = injectionConfigMap();

        FastAutoGenerator fastAutoGeneratorCustom = FastAutoGenerator.create(dataSourceProperties.getUrl(), dataSourceProperties.getUsername(), dataSourceProperties.getPassword())
                .globalConfig(builder -> {
                    builder.author(codeGeneratorProperty.getAuthor()) // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .outputDir(codeGeneratorProperty.getProjectPath() + "/src/main/java/"); // 指定输出目录
                })
                //注入配置
                .injectionConfig(injectionConfig -> {
                    injectionConfig.customMap(injectionConfigMap);
                })
                .packageConfig(builder -> {
                    builder.parent(codeGeneratorProperty.getParent()) // 设置父包名
                            .controller("api")
                            .moduleName(codeGeneratorProperty.getModuleName()) // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, "/tmp")); // 设置mapperXml生成路径
                })
                .templateConfig(builder -> {
                    builder.controller("/templates/air/api.java")
                            .disable(TemplateType.SERVICEIMPL, TemplateType.SERVICE, TemplateType.MAPPER, TemplateType.ENTITY);

                })
                .strategyConfig(builder -> {
                    if (codeGeneratorProperty.getIncludeTables() != null) {
                        builder.addExclude(codeGeneratorProperty.getIncludeTables().split(",")); // 设置需要生成的表名
                    }
                    builder.addTablePrefix(codeGeneratorProperty.getTablePrefix()); // 设置过滤表前缀
                    builder.controllerBuilder().formatFileName("%sApi");
                })
                .templateEngine(new FreemarkerTemplateEngine());// 使用Freemarker引擎模板，默认的是Velocity引擎模板

        fastAutoGeneratorCustom.execute();
    }

    private void generatorConvertor() {
        System.out.println("------------fastAutoGeneratorCustom generatorConvertor--------------");
        Map<String, Object> injectionConfigMap = injectionConfigMap();

        FastAutoGenerator fastAutoGeneratorCustom = FastAutoGenerator.create(dataSourceProperties.getUrl(), dataSourceProperties.getUsername(), dataSourceProperties.getPassword())
                .globalConfig(builder -> {
                    builder.author(codeGeneratorProperty.getAuthor()) // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .outputDir(codeGeneratorProperty.getOutputDir() + "storages/src/main/java"); // 指定输出目录
                })
                //注入配置
                .injectionConfig(injectionConfig -> {
                    injectionConfig.customMap(injectionConfigMap);
                })
                .packageConfig(builder -> {
                    builder.parent(codeGeneratorProperty.getParent() + ".storages") // 设置父包名
                            .controller("convertor")
                            .moduleName(codeGeneratorProperty.getModuleName()) // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, "/tmp")); // 设置mapperXml生成路径
                })
                .templateConfig(builder -> {
                    builder.controller("/templates/air/convertor.java")
                            .disable(TemplateType.SERVICEIMPL, TemplateType.SERVICE, TemplateType.MAPPER, TemplateType.ENTITY);

                })
                .strategyConfig(builder -> {
                    if (codeGeneratorProperty.getIncludeTables() != null) {
                        builder.addExclude(codeGeneratorProperty.getIncludeTables().split(",")); // 设置需要生成的表名
                    }
                    builder.addTablePrefix(codeGeneratorProperty.getTablePrefix()); // 设置过滤表前缀
                    builder.controllerBuilder().formatFileName("%sConvertor");
                })
                .templateEngine(new FreemarkerTemplateEngine());// 使用Freemarker引擎模板，默认的是Velocity引擎模板

        fastAutoGeneratorCustom.execute();
    }

    private void generatorInfrastructure() {
        System.out.println("------------fastAutoGeneratorCustom generatorInfrastructure--------------");
        Map<String, Object> injectionConfigMap = injectionConfigMap();

        FastAutoGenerator fastAutoGeneratorCustom = FastAutoGenerator.create(dataSourceProperties.getUrl(), dataSourceProperties.getUsername(), dataSourceProperties.getPassword())
                .globalConfig(builder -> {
                    builder.author(codeGeneratorProperty.getAuthor()) // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .outputDir(codeGeneratorProperty.getOutputDir() + "infrastructure/src/main/java"); // 指定输出目录
                })
                //注入配置
                .injectionConfig(injectionConfig -> {
                    injectionConfig.customMap(injectionConfigMap);
                })
                .packageConfig(builder -> {
                    builder.parent(codeGeneratorProperty.getParent() + ".infrastructure") // 设置父包名
                            .moduleName(codeGeneratorProperty.getModuleName()) // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, codeGeneratorProperty.getOutputDir() + "infrastructure/src/main/resources/mapper/" + codeGeneratorProperty.getModuleName())); // 设置mapperXml生成路径
                })
                .templateConfig(builder -> {
                    builder.mapper("/templates/air/mapper.java")
                            .xml("/templates/air/mapper.xml")
                            .disable(TemplateType.SERVICEIMPL, TemplateType.CONTROLLER, TemplateType.SERVICE, TemplateType.ENTITY);

                })
                .strategyConfig(builder -> {
                    if (codeGeneratorProperty.getIncludeTables() != null) {
                        builder.addExclude(codeGeneratorProperty.getIncludeTables().split(",")); // 设置需要生成的表名
                    }
                    builder.addTablePrefix(codeGeneratorProperty.getTablePrefix()); // 设置过滤表前缀
                })
                .templateEngine(new FreemarkerTemplateEngine());// 使用Freemarker引擎模板，默认的是Velocity引擎模板

        fastAutoGeneratorCustom.execute();
    }


    /**
     * @param modelName
     */
    private void generatorPomXml(String modelName) {
        System.out.println("------------fastAutoGeneratorCustom generatorPomXml--------------");
        Map<String, Object> injectionConfigMap = injectionConfigMap();
        injectionConfigMap.put("PomName", modelName);
        FastAutoGenerator fastAutoGeneratorCustom = FastAutoGenerator.create(dataSourceProperties.getUrl(), dataSourceProperties.getUsername(), dataSourceProperties.getPassword())
                .globalConfig(builder -> {
                    builder.author(codeGeneratorProperty.getAuthor()) // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .outputDir(codeGeneratorProperty.getOutputDir() + modelName); // 指定输出目录
                })
                //注入配置
                .injectionConfig(injectionConfig -> {
                    injectionConfig.customMap(injectionConfigMap);
                })
                .packageConfig(builder -> {
                    builder.parent(codeGeneratorProperty.getParent()) // 设置父包名
                            .moduleName(codeGeneratorProperty.getModuleName()) // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, codeGeneratorProperty.getOutputDir() + modelName)); // 设置mapperXml生成路径
                })
                .templateConfig(builder -> {
                    builder.xml("/templates/air/pom.xml")
                            .disable(TemplateType.SERVICEIMPL, TemplateType.CONTROLLER, TemplateType.SERVICE, TemplateType.ENTITY, TemplateType.MAPPER);

                })
                .strategyConfig(builder -> {
                    builder.mapperBuilder().formatXmlFileName("pom");
                })
                .templateEngine(new FreemarkerTemplateEngine());// 使用Freemarker引擎模板，默认的是Velocity引擎模板

        fastAutoGeneratorCustom.execute();
    }


    /**
     * 生成配置文件
     * @param configType
     */
    private void generatorConfig(String configType) {
        System.out.println("------------fastAutoGeneratorCustom generatorConfig--------------");
        Map<String, Object> injectionConfigMap = injectionConfigMap();

        FastAutoGenerator fastAutoGeneratorCustom = FastAutoGenerator.create(dataSourceProperties.getUrl(), dataSourceProperties.getUsername(), dataSourceProperties.getPassword())
                .globalConfig(builder -> {
                    builder.author(codeGeneratorProperty.getAuthor()) // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .outputDir(codeGeneratorProperty.getProjectPath() + "/src/main/java/"); // 指定输出目录
                })
                //注入配置
                .injectionConfig(injectionConfig -> {
                    injectionConfig.customMap(injectionConfigMap);
                })
                .packageConfig(builder -> {
                    builder.parent(codeGeneratorProperty.getParent()) // 设置父包名
                            .controller("config")
                            .moduleName(codeGeneratorProperty.getModuleName()); // 设置父包模块名
                })
                .templateConfig(builder -> {
                    String template = "";
                    if (configType.equals("swagger")) {
                        template = "/templates/air/swagger3Config.java";
                    }
                    if (configType.equals("cors")) {
                        template = "/templates/air/corsConfig.java";
                    }
                    if (configType.equals("redisson")) {
                        template = "/templates/air/redissonConfig.java";
                    }
                    builder.controller(template)
                            .disable(TemplateType.SERVICEIMPL, TemplateType.SERVICE, TemplateType.MAPPER, TemplateType.ENTITY, TemplateType.XML);

                })
                .strategyConfig(builder -> {
                    if (codeGeneratorProperty.getIncludeTables() != null) {
                        builder.addExclude(codeGeneratorProperty.getIncludeTables().split(",")); // 设置需要生成的表名
                    }
                    builder.addTablePrefix(codeGeneratorProperty.getTablePrefix()); // 设置过滤表前缀
                    if (configType.equals("swagger")) {
                        builder.controllerBuilder().formatFileName("Swagger3Config");
                    }
                    if (configType.equals("cors")) {
                        builder.controllerBuilder().formatFileName("CORSConfig");
                    }

                })
                .templateEngine(new FreemarkerTemplateEngine());// 使用Freemarker引擎模板，默认的是Velocity引擎模板

        fastAutoGeneratorCustom.execute();
    }

    /**
     * 注入配置变量
     *
     * @return
     */
    private Map<String, Object> injectionConfigMap() {
        Map<String, Object> injectionConfigMap = new HashMap<>();
        String moduleNameName = codeGeneratorProperty.getModuleName();
        if (StringUtils.isNotEmpty(moduleNameName)) {
            moduleNameName = "." + moduleNameName;
        }

        injectionConfigMap.put("Api", codeGeneratorProperty.getParent() + moduleNameName + ".api");
        injectionConfigMap.put("Po", codeGeneratorProperty.getParent() + ".storages" + moduleNameName + ".po");
        injectionConfigMap.put("Vo", codeGeneratorProperty.getParent() + ".storages" + moduleNameName + ".vo");
        injectionConfigMap.put("Dto", codeGeneratorProperty.getParent() + ".storages" + moduleNameName + ".dto");
        injectionConfigMap.put("Entity", codeGeneratorProperty.getParent() + ".storages" + moduleNameName + ".entity");
        injectionConfigMap.put("Service", codeGeneratorProperty.getParent() + ".services" + moduleNameName + ".service");
        injectionConfigMap.put("DomainService", codeGeneratorProperty.getParent() + ".services" + moduleNameName + ".domainService");
        injectionConfigMap.put("ServiceImpl", codeGeneratorProperty.getParent() + ".services" + moduleNameName + ".service.impl");
        injectionConfigMap.put("DomainServiceImpl", codeGeneratorProperty.getParent() + ".services" + moduleNameName + ".domainService.impl");
        injectionConfigMap.put("Convertor", codeGeneratorProperty.getParent() + ".storages" + moduleNameName + ".convertor");
        injectionConfigMap.put("Config", codeGeneratorProperty.getParent() + moduleNameName + ".config");
        injectionConfigMap.put("Parent", codeGeneratorProperty.getParent());
        injectionConfigMap.put("Handler", codeGeneratorProperty.getParent() + moduleNameName + ".handler");
        injectionConfigMap.put("GroupId", codeGeneratorProperty.getGroupId());
        injectionConfigMap.put("Version", codeGeneratorProperty.getVersion());
        injectionConfigMap.put("ArtifactId", codeGeneratorProperty.getArtifactId());
        injectionConfigMap.put("Mapper", codeGeneratorProperty.getParent() + ".infrastructure" + moduleNameName + ".mapper");
        injectionConfigMap.put("PomName", null);
        injectionConfigMap.put("ApiPathPre", StringUtils.isEmpty(codeGeneratorProperty.getModuleName()) ? "" : codeGeneratorProperty.getModuleName() + "/");


        return injectionConfigMap;
    }
}
